package edu.whut.mall.portal.service.impl;

import com.github.pagehelper.PageHelper;
import edu.whut.mall.common.api.CommonPage;
import edu.whut.mall.common.api.CommonResult;
import edu.whut.mall.common.api.ResultCode;
import edu.whut.mall.common.exception.MallException;
import edu.whut.mall.mapper.*;
import edu.whut.mall.model.*;
import edu.whut.mall.portal.async.GroupBuyAsyncService;
import edu.whut.mall.portal.dto.GroupBuyQualificationResult;
import edu.whut.mall.portal.enums.*;
import edu.whut.mall.portal.mapper.GroupBuyOrderCustomMapper;
import edu.whut.mall.portal.mapper.GroupBuyRuleCustomMapper;
import edu.whut.mall.portal.service.IPayInfoService;
import edu.whut.mall.portal.service.IPortalGroupBuyService;
import edu.whut.mall.portal.vo.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @program: d9lab-mall
 * @description: 用户团购实现类
 * @author: Wayne
 * @create: 2020-05-17 20:42
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class PortalGroupBuyServiceImpl implements IPortalGroupBuyService {

    private final GroupBuyCategoryMapper groupBuyCategoryMapper;

    private final GroupBuyRuleMapper groupBuyRuleMapper;

    private final GroupBuyRuleCustomMapper groupBuyRuleCustomMapper;

    private final UserGroupBuyRuleCountMapper userGroupBuyRuleCountMapper;

    private final GroupBuyRecordMapper groupBuyRecordMapper;

    private final UserMapper userMapper;

    private final GroupBuyRecordUserMapper groupBuyRecordUserMapper;

    private final GroupBuyAsyncService groupBuyAsyncService;

    private final GroupBuyOrderCustomMapper groupBuyOrderCustomMapper;

    private final ProductCategoryMapper productCategoryMapper;

    private IPayInfoService payInfoService;

    @Autowired
    public void setPayInfoService(IPayInfoService payInfoService) {
        this.payInfoService = payInfoService;
    }

    @Override
    public CommonPage<GroupBuyCategoryVo> listGroupBuyCategoryVos(Integer pageNum, Integer size) {
        PageHelper.startPage(pageNum, size);
        GroupBuyCategoryExample groupBuyCategoryExample = new GroupBuyCategoryExample();
        groupBuyCategoryExample.setOrderByClause("sort");
        groupBuyCategoryExample.createCriteria().andStatusEqualTo(1).andIsDeletedEqualTo(0);
        List<GroupBuyCategory> groupBuyCategoryList = groupBuyCategoryMapper.selectByExample(groupBuyCategoryExample);
        List<GroupBuyCategoryVo> groupBuyCategoryVoList = groupBuyCategoryList.stream().map(this::transCategory2Vo).collect(Collectors.toList());
        return CommonPage.restPage(groupBuyCategoryVoList);
    }

    @Override
    public CommonPage<GroupBuyRuleVo> listGroupBuyRuleVosByCategoryId(Long categoryId, Integer pageNum, Integer size) {
        PageHelper.startPage(pageNum, size);
        List<GroupBuyRuleVo> groupBuyRuleVoList = groupBuyRuleCustomMapper.listGroupBuyRuleVoByCategoryId(categoryId);
        return CommonPage.restPage(groupBuyRuleVoList);
    }

    @Override
    @Transactional
    public GroupBuyQualificationResult createGroupBuyRecord(Long userId, Long groupBuyRuleId, String orderId) throws MallException, NoSuchAlgorithmException {
        GroupBuyRecord groupBuyRecord = new GroupBuyRecord();
        GroupBuyRule groupBuyRule = groupBuyRuleMapper.selectByPrimaryKey(groupBuyRuleId);
        //检查有没有资格开启此次团购
        GroupBuyQualificationResult qualificationResult = isQualifiedToCreateGroupBuyRecord(userId, groupBuyRuleId);
        if (!qualificationResult.isQualified()) {
            refundGroupBuyRecord(orderId);
            return qualificationResult;
        }
        Date now = new Date();
        groupBuyRecord.setStartTime(now);
        groupBuyRecord.setCurrentNumber(1);
        groupBuyRecord.setSuccessNumber(groupBuyRule.getSuccessPeopleNumber());
        groupBuyRecord.setGroupBuyRuleId(groupBuyRuleId);
        groupBuyRecord.setGroupBuyPrice(groupBuyRule.getGroupBuyPrice());
        groupBuyRecord.setExpireTime(DateUtils.addMinutes(now, groupBuyRule.getValidTime()));
        groupBuyRecord.setStatus(GroupBuyRecordStatusEnum.GROUP_BUY_PROCESSING.getCode());
        groupBuyRecordMapper.insertSelective(groupBuyRecord);
        updateUserGroupBuyCount(userId, groupBuyRuleId, qualificationResult.getBuyCount());
        insertUserInfo2GroupBuyRecord(userId, groupBuyRecord.getId(), GroupBuyUserTypeEnum.GROUP_BUY_CREATE.getCode(), orderId);
        return qualificationResult;
    }

    @Transactional
    @Override
    public GroupBuyQualificationResult joinGroupBuyRecord(Long userId, Long groupBuyRecordId, String orderId) throws NoSuchAlgorithmException {
        GroupBuyRecord record = groupBuyRecordMapper.selectByPrimaryKey(groupBuyRecordId);
        GroupBuyRule rule = groupBuyRuleMapper.selectByPrimaryKey(record.getGroupBuyRuleId());
        GroupBuyQualificationResult result = isQualifiedToJoinGroupBuyRecord(userId, groupBuyRecordId, rule.getLimitNumber());
        if (!result.isQualified()){
            refundGroupBuyRecord(orderId);
            return result;
        }
        updateUserGroupBuyCount(userId, record.getGroupBuyRuleId(), result.getBuyCount());
        insertUserInfo2GroupBuyRecord(userId, groupBuyRecordId, GroupBuyUserTypeEnum.GROUP_BUY_JOIN.getCode(), orderId);
        GroupBuyRecord updateRecord = new GroupBuyRecord();
        updateRecord.setId(record.getId());
        updateRecord.setCurrentNumber(record.getCurrentNumber() + 1);
        updateRecord.setUpdateTime(new Date());
        groupBuyRecordMapper.updateByPrimaryKeySelective(updateRecord);
        //查询团购规则 是否可以开团发货
        if (record.getSuccessNumber().equals(updateRecord.getCurrentNumber())) {
            log.info("团购record:{}开团成功,进入异步方法", record.getId());
            groupBuyAsyncService.SuccessGroupBuyOrder(record.getId());
        }
        return result;
    }

    /**
     * 退款
     * @param orderId
     * @throws NoSuchAlgorithmException
     */
    public void refundGroupBuyRecord(String orderId) throws NoSuchAlgorithmException {
        CommonResult result = payInfoService.refund(orderId);
        if (ResultCode.SUCCESS.getCode() == result.getCode()) {
            payInfoService.updateGroupBuyOrderStatus(orderId, OrderStatusEnum.REFUNDED.getCode());
            payInfoService.updatePayInfoStatus(orderId, PaymentStatusEnum.REFUNDED.getCode());
        }
    }


    @Override
    public GroupBuyQualificationResult isQualifiedToJoinGroupBuyRecord(Long userId, Long recordId, Integer ruleLimitNumber) {
        GroupBuyQualificationResult firstResult = checkIfCanJoinGroupBuyRecord(userId, recordId, ruleLimitNumber);
//        if (firstResult.isQualified()) {
//            return checkGroupBuyCount(userId, firstResult);
//        }
//        return firstResult;
        return firstResult;
    }

    @Override
    public GroupBuyQualificationResult isQualifiedToCreateGroupBuyRecord(Long userId, Long ruleId)throws MallException {
        //检查团购规则状态
        GroupBuyQualificationResult firstResult = checkIfCanCreateGroupBuyRecord(ruleId);
//        if (firstResult.isQualified()) {
//            //团购规则状态没问题,是否超过次数
//            return checkGroupBuyCount(userId, firstResult);
//        }
//        else{
//            return firstResult;
//        }
        return firstResult;
    }

    @Override
    public GroupBuyRecordDetailVo getGroupBuyRecordDetailVoByRecordId(Long recordId){
        return groupBuyOrderCustomMapper.getGroupBuyRecordDetailVoByRecordId(recordId);
    }

    @Override
    public GroupBuyRuleDetailVo getGroupBuyRuleDetailVosByRuleId(Long ruleId) {
        return groupBuyRuleCustomMapper.getRuleDetailVoByPrimaryKey(ruleId);
    }



    @Override
    public List<ProductCategoryVo> listProductCategoryVos() {
        List<ProductCategory> categoryList = productCategoryMapper.selectByExample(new ProductCategoryExample());
        List<ProductCategoryVo> categoryVoList = categoryList.stream().map(productCategory -> {
            ProductCategoryVo productCategoryVo = new ProductCategoryVo();
            BeanUtils.copyProperties(productCategory, productCategoryVo);
            return productCategoryVo;
        }).collect(Collectors.toList());
        return categoryVoList;
    }

    @Override
    public List<GroupBuyRuleVo> listGroupBuyRuleVosByProductCategory(Long categoryId) {
        return groupBuyRuleCustomMapper.listGroupBuyRuleVosByProductCategory(categoryId);
    }

    @Override
    public List<GroupBuyRuleVo> getGroupBuyRuleVoBySearchingName(String productName) {
        return groupBuyRuleCustomMapper.getGroupBuyRuleVoBySearchingName(productName);
    }

    /**
     * 检查团购规则状态
     * 这代表检查它是否存在,是否过期或者是否下架
     * @param ruleId
     */
    private GroupBuyQualificationResult checkIfCanCreateGroupBuyRecord(Long ruleId) throws MallException {
        GroupBuyRule groupBuyRule = groupBuyRuleMapper.selectByPrimaryKey(ruleId);
        Date now =new Date();
        if (groupBuyRule == null){
            return GroupBuyQualificationResult.fail("团购规则不存在");
        }
        if (GroupBuyRuleStatusEnum.DISABLE.getCode().equals(groupBuyRule.getStatus())){
            return GroupBuyQualificationResult.fail("团购规则已下架，不能发起团购");
        }
        //检查团购规则是否过期
        if (groupBuyRule.getStartTime().getTime() > now.getTime() || groupBuyRule.getEndTime().getTime() < now.getTime()){
            return GroupBuyQualificationResult.fail("团购规则已经过期，不能发起团购");
        }
        return GroupBuyQualificationResult.successWithRuleId(ruleId, groupBuyRule.getLimitNumber());
    }

    /**
     * 检查已经参加或者发起的团购次数是否超过限制次数
     * @param userId
     * @param firstResult
     * @return 返回已经购买的次数
     */
    private GroupBuyQualificationResult checkGroupBuyCount(Long userId, GroupBuyQualificationResult firstResult)throws MallException{
        UserGroupBuyRuleCountExample userGroupBuyRuleCountExample = new UserGroupBuyRuleCountExample();
        userGroupBuyRuleCountExample.createCriteria().andUserIdEqualTo(userId).andGroupBuyRuleIdEqualTo(firstResult.getGroupBuyRuleId());
        List<UserGroupBuyRuleCount> userGroupBuyRuleCount = userGroupBuyRuleCountMapper.selectByExample(userGroupBuyRuleCountExample);
        if (CollectionUtils.isEmpty(userGroupBuyRuleCount)) {
            return GroupBuyQualificationResult.successWithCount(0);
        }
        int buyCount = userGroupBuyRuleCount.get(0).getCount();
        if (buyCount >= firstResult.getRuleLimitNumber()) {
           return GroupBuyQualificationResult.fail("超过参团次数，不能参团");
        }
        return GroupBuyQualificationResult.successWithCount(buyCount);
    }

    /**
     * 更新用户购买次数
     * @param userId
     * @param groupBuyRuleId
     * @param formerBuyCount
     */

    private void updateUserGroupBuyCount(Long userId, Long groupBuyRuleId, Integer formerBuyCount){
        UserGroupBuyRuleCount userGroupBuyRuleCount = new UserGroupBuyRuleCount();
        userGroupBuyRuleCount.setUserId(userId);
        userGroupBuyRuleCount.setGroupBuyRuleId(groupBuyRuleId);
        if (formerBuyCount > 0) {
            userGroupBuyRuleCount.setCount(formerBuyCount + 1);
            userGroupBuyRuleCountMapper.updateByPrimaryKeySelective(userGroupBuyRuleCount);
        }
        else{
            userGroupBuyRuleCount.setCount(1);
            userGroupBuyRuleCountMapper.insertSelective(userGroupBuyRuleCount);
        }
    }

    /**
     * 插入用户团购记录 ->用户记录和团购就绑定
     * @param userId
     * @param groupBuyRecordId
     * @param userType
     * @param orderId
     * @return
     */
    private int insertUserInfo2GroupBuyRecord(Long userId, Long groupBuyRecordId, Integer userType, String orderId){
        GroupBuyRecordUser groupBuyRecordUser = new GroupBuyRecordUser();
        User user = userMapper.selectByPrimaryKey(userId);
        groupBuyRecordUser.setUserId(userId);
        groupBuyRecordUser.setUsername(user.getNickname());
        groupBuyRecordUser.setUserPic(user.getPicture());
        groupBuyRecordUser.setRecordId(groupBuyRecordId);
        groupBuyRecordUser.setOrderId(orderId);
        groupBuyRecordUser.setUserType(userType);
        return groupBuyRecordUserMapper.insertSelective(groupBuyRecordUser);
    }

    /**
     * 检查团购记录状态
     * @Param recordId
     * @Param limitNumber
     */
    private GroupBuyQualificationResult checkIfCanJoinGroupBuyRecord(Long userId, Long recordId, Integer limitNumber){
        GroupBuyRecord record = groupBuyRecordMapper.selectByPrimaryKey(recordId);
        if (record == null){
            return GroupBuyQualificationResult.fail( "团购记录不存在，不能参团");
        }
        Date now = new Date();
        if (record.getCurrentNumber() >= record.getSuccessNumber()){
            return GroupBuyQualificationResult.fail( "成团人数已满，不能参团");
        }
        if (now.getTime() > record.getExpireTime().getTime()){
            return GroupBuyQualificationResult.fail( "团购已经过期，不能参团");
        }
        if (!GroupBuyRecordStatusEnum.GROUP_BUY_PROCESSING.getCode().equals(record.getStatus())){
            return GroupBuyQualificationResult.fail( "团购状态不对，不能参团");
        }
        boolean isJoined = groupBuyOrderCustomMapper.checkIfJoinedGroupBuyRecord(recordId, userId) > 0 ;
        if (isJoined) {
            return GroupBuyQualificationResult.fail( "已经加入此次团购");
        }
        return GroupBuyQualificationResult.successWithRuleId(record.getGroupBuyRuleId(), limitNumber);

    }


    /**
     * 将团购分类转换成展示层
     * @param groupBuyCategory
     * @return
     */
    public GroupBuyCategoryVo transCategory2Vo(GroupBuyCategory groupBuyCategory){
        GroupBuyCategoryVo groupBuyCategoryVo = new GroupBuyCategoryVo();
        BeanUtils.copyProperties(groupBuyCategory, groupBuyCategoryVo);
        return groupBuyCategoryVo;
    }

    /**
     * 将团购规则转换成展示层
     * @param groupBuyRule
     * @return
     */
    public GroupBuyRuleVo transRule2Vo(GroupBuyRule groupBuyRule){
        GroupBuyRuleVo groupBuyRuleVo = new GroupBuyRuleVo();
        BeanUtils.copyProperties(groupBuyRule, groupBuyRuleVo);
        return groupBuyRuleVo;
    }


}
